/**
 * 遍历ast语法树
 * @param {object} node ast树的节点
 * @param {function} enter_leave 进入函数 和 离开函数
 */
const walk = (node, { enter, leave }) => {
    visit(node, null, enter, leave);
}

/**
 * ast的访问者
 * @param {object} node ast树的节点
 * @param {object|null} parent 当前节点的父节点
 * @param {function} enter 进入节点时的回调方法
 * @param {function} leave 退出节点时的回调方法
 */
const visit = (node, parent, enter, leave) => {
    if(typeof node !== "object" || node === null) return;

    enter && enter(node, parent);

    /*  得到当前node节点的属性值为对象的所有属性名
        {
            type: "FunctionDeclaration",
            start: 1,
            end: 13,
            loc: SourceLocation {
                start: Position { line: 3, column: 0 },
                end: Position { line: 5, column: 1 }
            },
            range: [ 1, 13 ],
            declarations: [
                Node {
                    type: 'VariableDeclarator',
                    start: 7,
                    end: 12,
                    loc: [SourceLocation],
                    range: [Array],
                    id: [Node],
                    init: [Node]
                }
            ],
        }
    */

    // objectKey ====> ["loc", "range", "declarations"]
    const objectKeys = Object.keys(node).filter(nodeKey => typeof node[nodeKey] === "object");
    objectKeys.forEach(propKey => {
        const value = node[propKey]; // 因为value的类型是object，所以value可能是数组，也可能是对象
        if(Array.isArray(value)) {
            // 如果是子节点是数组，则递归遍历
            value.forEach(item => visit(item, node, enter, leave));
        } else {
            visit(value, node, enter, leave);
        }
    })

    leave && leave(node, parent);
}

module.exports = walk;